﻿/*** FFIRCH2 Class - FlashFurc Core
 * ---
 * Author: IceDragon <icedragon@quickfox.org>
 * Web:    www.icerealm.org
 * ---
 * 
 * Copyright (c) 2010, IceRealm.org
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   # Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   # Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   # Neither the name of the IceRealm.org nor the names of its contributors
 *     may be used to endorse or promote products derived from this software
 *     without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Collections.Generic;
using System.IO;

using LibRCH2;

namespace FlashFurc
{
    /// <summary>
    /// (FlashFurc Installer)
    /// This class handles Furcadia installation from an existing local install
    /// to the target medium.
    /// </summary>
    public class FFIRCH2 : FlashFurcInstaller
    {
        /*** Constructors ****************************************************/
        public FFIRCH2(string rch2file) : base()
        {
            container = FurcadiaInstaller.GetFileContainer(rch2file);
            if (container == null)
                throw new Exception("Unable to find RCH2 container within the given file");

            Init();
        }
        public FFIRCH2(RCH2Container newContainer) : base()
        {
            container = newContainer;
            Init();
        }

        /*** Methods *********************************************************/
        public override void Run()
        {
            // We can't start if the target was unspecified.
            if (Settings.InstallTarget == null)
                throw new NotAvailableException("Install target not specified!");

            busy = true;

            // Create the necessary folders on the target medium.
            Status = "Creating main directory...";
            DirectoryInfo diRoot = new DirectoryInfo(Settings.InstallTarget);
            if (!diRoot.Exists)
                diRoot.Create();

            DirectoryInfo diData = diRoot.CreateSubdirectory(DATA_FOLDER);

            // Transfer the files to the target medium.
            foreach (RCH2File file in container.Files)
            {
                // Count even the ignored files in because we didn't separate
                // them in the total counts. If we don't, there will be
                // misinformation...
                CurrentFile++;
                CurrentSize += file.Size;

                // Skip ignored and lnk files if any
                if (IGNORED_FILES.Contains(file.Filename.ToLower()) || file.Filename.EndsWith(".lnk"))
                    continue;

                string targetPath = TranslatePath(file.Path);
                Status = "Extracting files: " + targetPath;

                try
                {
                    file.Extract(targetPath);
                }
                catch (DirectoryNotFoundException ex)
                {
                    FileInfo fi = new FileInfo(targetPath);
                    fi.Directory.Create();
                    file.Extract(targetPath); // Try again
                }
            }

            // Install character files.
            string data_path = diData.FullName;
            foreach (FileInfo fi in CharacterFiles)
            {
                Status = "Copying character file " + fi.Name;

                // If we end up having duplicate files, make sure both end up
                // inside.
                string filename;
                int i = 1;
                do
                {
                    string name = fi.Name.Split('.')[0] +
                        ((i > 1) ? i.ToString() : "") +
                        fi.Extension;

                    filename = data_path + Path.DirectorySeparatorChar + name;
                } while (File.Exists(filename));

                fi.CopyTo(filename);
            }

            // Create the localdir.ini and fill it with a relative path.
            CreateLocaldir(diRoot);

            // All done! (hopefully)
            busy = false;
        }

        #region Private Stuff
        /*** Methods *********************************************************/
        /// <summary>
        /// Perform initialization work after RCH2 container assignment by the
        /// constructor.
        /// </summary>
        private void Init()
        {
            Available = true;
            TotalFiles = container.Count;

            // Calculate TotalSize
            TotalSize = 0;
            foreach (RCH2File file in container.Files)
                TotalSize += file.Size;
        }

        /// <summary>
        /// Translate a given installer path into a full target path.
        /// </summary>
        /// <param name="filepath">File path from a furcsetup path</param>
        /// <returns>Full target install path of the given file</returns>
        private string TranslatePath(string filepath)
        {
            if (filepath.StartsWith("$INSTALLDIR$"))
                return Settings.InstallTarget +
                    Path.DirectorySeparatorChar +
                    filepath.Substring(12);

            if (filepath.StartsWith("%USERDATA%"))
                return Settings.InstallTarget +
                    Path.DirectorySeparatorChar +
                    DATA_FOLDER +
                    Path.DirectorySeparatorChar +
                    filepath.Substring(19); // Also skip the "\Furcadia" bit!

            if (filepath.StartsWith("%ALLUSERSPROFILE%"))
            {
                // We'll be reading the first folder to determine the target
                // folder, so take care of the initial \ if any.
                int l = (filepath[17] == '\\') ? 17 : 18;
                string[] fpElements = filepath.Substring(l).Split(new char[] {'\\'}, 2);
                
                string newFolder;
                switch (fpElements[0])
                {
                    case "Temporary Dreams":
                    case "Temporary Files":
                        newFolder = "tmp";
                        break;
                    case "Permanent Maps":
                        newFolder = "maps";
                        break;
                    case "Dynamic Avatars":
                        newFolder = "skins";
                        break;
                    case "Portrait Cache":
                        newFolder = "portraits";
                        break;
                    default:
                        newFolder = "";
                        break;
                }

                return Settings.InstallTarget +
                    Path.DirectorySeparatorChar +
                    DATA_FOLDER +
                    Path.DirectorySeparatorChar +
                    newFolder +
                    Path.DirectorySeparatorChar +
                    fpElements[1];
            }

            return filepath;
        }

        /*** Members *********************************************************/
        private RCH2Container container;
        #endregion
    }
}